package com.suemi.rpc.codec;

import com.suemi.rpc.entity.RpcHeader;
import com.suemi.rpc.entity.RpcMessage;
import com.suemi.rpc.util.SerializationUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

import java.util.Map;
import java.util.zip.CRC32;

public class RpcMessageEncoder extends MessageToByteEncoder<RpcMessage> {
  @Override
  protected void encode(ChannelHandlerContext ctx, RpcMessage msg, ByteBuf out) throws Exception {
    if (msg == null || msg.getHeader() == null)
      throw new IllegalArgumentException("Message format not legal!");

    RpcHeader header = msg.getHeader();

    out.writeLong(header.getCrcCode());
    out.writeInt(header.getLength());
    out.writeLong(header.getSender());
    out.writeByte(header.getType().value());
    out.writeInt(header.getAttachments().size());

    String key;
    byte[] keyArray;
    String value;
    byte[] valueArray;

    for (Map.Entry<String, String> entry : msg.getHeader().getAttachments().entrySet()) {
      key = entry.getKey();
      keyArray = key.getBytes("UTF-8");
      out.writeInt(keyArray.length);
      out.writeBytes(keyArray);
      value = entry.getValue();
      valueArray = value.getBytes("UTF-8");
      out.writeInt(valueArray.length);
      out.writeBytes(valueArray);
    }

    int bodyStart = out.writerIndex();
    out.writeInt(0);

    if (msg.getBody() != null) {
      out.writeBytes(SerializationUtil.serialize(msg.getBody()));
      out.setInt(bodyStart, out.writerIndex() - bodyStart - 4);
    }

    out.setInt(8, out.readableBytes() - 12);

    byte[] tmp = new byte[out.readableBytes() - 8];
    out.getBytes(8, tmp);

    CRC32 crc = new CRC32();
    crc.update(tmp);
    out.setLong(0, crc.getValue());
  }
}
